<?php

namespace AppBundle\Controller\Api;

use AppBundle\Constants\Constant;
use AppBundle\Services\DB2Service;
use AppBundle\Services\ForwardService;
use AppBundle\Services\HandleConfigSerivice;
use AppBundle\Services\LogService;
use AppBundle\Util\Gateway\GatewayUtil;
use ClassesWithParents\G;
use JMS\Serializer\Tests\Fixtures\Timestamp;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\Controller\Annotations\Post;
use Symfony\Component\Routing\Annotation\Route;
use AppBundle\Controller\BaseApiController;
use SimpleXMLElement;

/**
 * Description of APIController
 *
 * @author maple
 */
class APIController extends BaseApiController
{

    private $logId;

    /**
     * @return Response
     * --@Post("/handle", name="app_api_event_handle", options={"method_prefix"=false})
     * @Route("/handle", name="app_api_event_handle", options={"method_prefix"=false})
     * @param Request $request
     */
    public function handleAction(Request $request)
    {
        $start = date('Y-m-d H:i:s', time());
        $content = $request->getContent();

        $logId = $this->getLogService()->initLog([
            'startTime' => $start,
            'requestMsg' => $content
        ]);

        $this->logId = $logId;

        $eventType = $request->query->get('eventType');
        $this->logDebug('[APIController handleAction] event type: ' . $eventType . ', request content: ' . $content);

        $contentXml = null;
        $headers = null;
        $senderId = null;
        $senderSN = null;
        $tradeCode = null;
        $senderDate = null;
        $senderTime = null;
        $bodyNodes = null;
        $body = null;
        try {
            // 解析报文
            $contentXml = simplexml_load_string($content);
            $headers = $contentXml->xpath('/soapenv:Envelope/soapenv:Header/gateway:HeadType')[0];
            $senderId = (string)($contentXml->xpath('/soapenv:Envelope/soapenv:Header/gateway:HeadType/gateway:senderId')[0]);
            $senderSN = (string)($contentXml->xpath('/soapenv:Envelope/soapenv:Header/gateway:HeadType/gateway:senderSN')[0]);
            $tradeCode = (string)($contentXml->xpath('/soapenv:Envelope/soapenv:Header/gateway:HeadType/gateway:tradeCode')[0]);
            $senderDate = (string)($contentXml->xpath('/soapenv:Envelope/soapenv:Header/gateway:HeadType/gateway:senderDate')[0]);
            $senderTime = (string)($contentXml->xpath('/soapenv:Envelope/soapenv:Header/gateway:HeadType/gateway:senderTime')[0]);

            $bodyNodes = $contentXml->xpath('/soapenv:Envelope/soapenv:Body/gateway:NoAS400')[0];
            $body = $this->getGatewayUtil()->parse2XML($bodyNodes);

            // 记录解析出的报文Header部分有效数据
            $this->getLogService()->contentLog([
                'senderId' => $senderId,
                'senderSN' => $senderSN,
                'tradeCode' => $tradeCode,
                'requestTime' => $senderDate . $senderTime,
                'rowId' => $logId
            ]);

            // 获取接口配置
            $handle = $this->getHandleConfigSerivice()->getHandleConfigByCode($eventType);
            if (empty($handle)) {
                $this->logError('[APIController handleAction] The eventType ' . $eventType . ' haven\'t config handle method');
                $errorCode = '1001';
                $errorMsg = '转发服务器没有配置这个接口';
                return $this->returnResult($errorCode, $errorMsg, $headers);
            }
            // 获取接口配置参数
            $whereParams = $this->getHandleConfigSerivice()->getWhereParamsByConfigCode($handle['ROW_ID']);
            $orderParams = $this->getHandleConfigSerivice()->getOrderParamsByConfigCode($handle['ROW_ID']);
            // 接口类型
            $type = $handle['INTERFACE_TYPE'];

            $result = array();
            $xml = '';
            if ($type == Constant::HANDLE_TYPE_DB2) {
                // 接口类型是DB2
                $result = $this->getDB2Service()->exec($handle['SQL_CONTENT'], $body, $whereParams, $orderParams);
                $errorCode = $result['errorCode'];
                $errorMsg = $result['errorMsg'];
                $xml = $this->renderXml($headers, $result);
            } else if ($type == Constant::HANDLE_TYPE_FORWARD) {
                // 接口类型是转发
                $result = $this->getForwardService()->forward($content, $handle['REQUEST_ADDR'], $handle['REQUEST_TYPE']);
                $errorCode = $result['errorCode'];
                $errorMsg = $result['errorMsg'];
                $xml = $this->$result['result'];
            } elseif ($type == Constant::HANDLE_TYPE_CUSTOM) {
                //TODO 自定义接口类型
                // 需要二次开发的接口
                // 需要在页面接口配置中配置Service和method
                // 在接到该类型接口请求时，根据配置写相应的处理方法
            }

            return $this->returnResult($errorCode, $errorMsg, $headers, $xml);
        } catch (\Exception $ex) {
            $this->logError('[APIController handleAction] Has exception, message: ' . $ex->getMessage());
            $errorCode = 9999;
            $errorMsg = '接口转发处理异常，异常信息： ' . $ex->getMessage();
            return $this->returnResult($errorCode, $errorMsg, $headers);
        }
    }

    private function returnResult($errorCode, $errorMsg, $header, $xml = null)
    {
        $end = date('Y-m-d H:i:s', time());
        if ($xml == null) {
            $data = array(
                'errorCode' => $errorCode,
                'errorMsg' => $errorMsg
            );
            $xml = $this->renderXml($header, $data);
        }
        $this->getLogService()->resultLog([
            'errorCode' => $errorCode,
            'errorMsg' => $errorMsg,
            'responseMsg' => $xml,
            'endTime' => $end,
            'rowId' => $this->logId
        ]);

        $response = new Response($xml);
        $response->headers->set('Content-Type', 'xml');
        return $response;
    }

    private function renderXml($headers, array $data = array())
    {
        $xml = simplexml_load_string('<?xml version="1.0" encoding="GBK"?>
            <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:gateway="http://www.agree.com.cn/GDBGateway">
                <soapenv:Header>
                    <gateway:HeadType soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0">
                    </gateway:HeadType>
                </soapenv:Header>
                <soapenv:Body>
                    <gateway:NoAS400>
                    </gateway:NoAS400>
                </soapenv:Body>
            </soapenv:Envelope>');

        $headerVals = $xml->xpath('/soapenv:Envelope/soapenv:Header/gateway:HeadType');
        $headerVal = $headerVals[0];

        /** @var SimpleXMLElement $header */
        foreach ($headers->children('http://www.agree.com.cn/GDBGateway') as $header) {
            $headerVal->addChild($header->getName(), (string)$header);
        }

        $bodyVals = $xml->xpath('/soapenv:Envelope/soapenv:Body/gateway:NoAS400');
        $bodyVal = $bodyVals[0];

        foreach ($data as $key => $value) {
            if ($key == 'errorCode') {
                $node = $bodyVal->addChild('gateway:field', $data['errorCode']);
                $node->addAttribute('name', 'errorCode');
            } elseif ($key == 'errorMsg') {
                $node = $bodyVal->addChild('gateway:field', $data['errorMsg']);
                $node->addAttribute('name', 'errorMsg');
            } elseif ($key == 'totalRows') {
                $node = $bodyVal->addChild('gateway:field', $data['totalRows']);
                $node->addAttribute('name', 'totalRows');
            } elseif ($key == 'totalPages') {
                $node = $bodyVal->addChild('gateway:field', $data['totalPages']);
                $node->addAttribute('name', 'totalPages');
            } elseif ($key == 'result') {
                $result = $data['result'];
                foreach ($result as $resKey => $resVal) {
                    if (is_array($resVal)) {
                        foreach ($resVal as $index => $val) {
                            $resultNode = $bodyVal->addChild('gateway:field', $val);
                            $resultNode->addAttribute('name', $index);
                        }
                    }
                }
            } else {
                $node = $bodyVal->addChild('gateway:field', $data['totalPages']);
                $node->addAttribute('name', $key);
            }
        }

        return $xml->asXML();
    }

    /**
     * @return GatewayUtil
     */
    private function getGatewayUtil()
    {
        return $this->get('app.util.gateway.gateway_util');
    }

    /**
     * @return DB2Service
     */
    private function getDB2Service()
    {
        return $this->get('app.db2_service');
    }

    /**
     * @return ForwardService
     */
    private function getForwardService()
    {
        return $this->get('app.forward_service');
    }

    /**
     * @return HandleConfigSerivice
     */
    private function getHandleConfigSerivice()
    {
        return $this->get('app.handle_config_service');
    }

    /**
     * @return LogService
     */
    private function getLogService()
    {
        return $this->get('app.log_service');
    }
}
